Open
Description
I encountered a problem when I try to update from 5.1.7 to 5.2.0
I am unable to apply child filter of "DeletedAt is NULL"
using System;
using System.Collections;
using System.Collections.Generic;
using FluentNHibernate.Cfg;
using FluentNHibernate.Cfg.Db;
using FluentNHibernate.Conventions.AcceptanceCriteria;
using FluentNHibernate.Conventions.Inspections;
using FluentNHibernate.Conventions.Instances;
using FluentNHibernate.Conventions;
using FluentNHibernate.Mapping;
using NHibernate;
using NHibernate.Util;
using FilterDefinition = FluentNHibernate.Mapping.FilterDefinition;
using FluentNHibernate.Conventions.Helpers;
using System.Linq;
namespace Testing.ManyToMany
{
internal class Program
{
public static void Main(string[] args)
{
Console.WriteLine("Testing NHibernate Many To Many relationship");
var version = typeof(ISession).Assembly.GetName().Version;
Console.WriteLine($"V: {version}");
var sessionFactory = CreateSessionFactory();
using (var session = sessionFactory.OpenSession())
{
session.EnableFilter(DeletedAtIsNullFilterConvention.NotDeletedFilter.FilterName);
using (var transaction = session.BeginTransaction())
{
Console.WriteLine("session.QueryOver<Webcam>().List();");
var webcamExist = session.QueryOver<Webcam>().List();
Console.WriteLine("var count1 = webcamExist[0].Supplies.Count;");
var count1 = webcamExist[0].Supplies.Count;
Console.WriteLine("var webcamByGet = session.Get<Webcam>(123241);");
var webcamByGet = session.Get<Webcam>(123241);
Console.WriteLine("var list = webcamByGet.Supplies.ToList();");
var list = webcamByGet.Supplies.ToList();
Console.WriteLine("var count2 = webcamByGet.Supplies.Count;");
var count2 = webcamByGet.Supplies.Count;
if (count2 == 0)
{
// NHibernate old version - 5.1.7 or below
Console.WriteLine("count2 = 0");
}
else {
// NHibernate new version - 5.2.0 or above
Console.WriteLine("count2 != 0");
}
var currency = new Currency()
{
Code = "",
LastDataVersion = 100500,
MinorUnitDecimalDigits = 7,
Name = "My currency",
NumericCode = 42,
};
session.SaveOrUpdate(currency);
var hardwareSupplier = new HardwareSupplier()
{
LastDataVersion = 100500,
Name = "supplier1",
PreferredCurrency = currency
};
session.SaveOrUpdate(hardwareSupplier);
var webcam = new Webcam()
{
LastDataVersion = 42,
Manufacturer = "Manufacturer",
Model = "Model 100500",
HasMic = true,
Price = 1.23M
};
var supply = new Supply()
{
LastDataVersion = 100500,
Number = 1,
HardwareSupplier = hardwareSupplier
};
supply.DeletedAt = DateTime.UtcNow;
webcam.DeletedAt = DateTime.UtcNow;
supply.Webcams.Add(webcam);
webcam.Supplies.Add(supply);
session.SaveOrUpdate(webcam);
session.SaveOrUpdate(supply);
transaction.Commit();
}
}
}
public static ISessionFactory CreateSessionFactory()
{
return Fluently.Configure()
.Database(MsSqlConfiguration.MsSql2005
.ShowSql()
.ConnectionString("Data Source=.;Initial Catalog=test_sm;User Id=sa;Password=Password123"))
.Mappings(m =>
m.FluentMappings
.Add<WebcamMap>()
.Add<SupplyMap>()
.Add<HardwareSupplierMap>()
.Add<CurrencyMap>()
.Add(typeof(DeletedAtIsNullFilterConvention.NotDeletedFilter))
//.Conventions.Add(Conventions.ToArray())
)
.BuildSessionFactory();
}
public static IEnumerable<IConvention> Conventions
{
get { return [DefaultLazy.Never(), new DeletedAtIsNullFilterConvention()]; }
}
}
public class Webcam
{
public virtual int Id { get; protected set; }
public virtual int LastDataVersion { get; set; }
public virtual string Manufacturer { get; set; }
public virtual string Model { get; set; }
public virtual decimal Price { get; set; }
public virtual bool HasMic { get; set; }
public virtual IDictionary Attributes { get; set; }
public virtual ISet<Supply> Supplies { get; set; } = new HashSet<Supply>();
public virtual DateTime DeletedAt { get; set; }
}
public class WebcamMap : ClassMap<Webcam>
{
public WebcamMap()
{
Schema("mod_list_management");
Table("DynWebcams");
Id(x => x.Id);
Map(x => x.LastDataVersion);
Map(x => x.Manufacturer);
Map(x => x.Model);
Map(x => x.Price);
Map(x => x.HasMic);
Map(x => x.DeletedAt);
ApplyFilter<DeletedAtIsNullFilterConvention.NotDeletedFilter>();
HasManyToMany(x => x.Supplies)
.Schema("mod_list_management")
.Table("DynSuppliesWebcams")
.ParentKeyColumn("WebcamId")
.ChildKeyColumn("SupplyId")
.ApplyChildFilter<DeletedAtIsNullFilterConvention.NotDeletedFilter>()
.Cascade.All()
;
}
}
public class Supply
{
public virtual int Id { get; protected set; }
public virtual int LastDataVersion { get; set; }
public virtual int Number { get; set; }
public virtual HardwareSupplier HardwareSupplier { get; set; }
public virtual IDictionary Attributes { get; set; }
public virtual ISet<Webcam> Webcams { get; set; } = new HashSet<Webcam>();
public virtual DateTime DeletedAt { get; set; }
}
public class SupplyMap : ClassMap<Supply>
{
public SupplyMap()
{
Schema("mod_list_management");
Table("DynSupplies");
Id(x => x.Id);
Map(x => x.LastDataVersion);
Map(x => x.Number);
Map(x => x.DeletedAt);
References(x => x.HardwareSupplier, "HardwareSupplierId").Cascade.All();
ApplyFilter<DeletedAtIsNullFilterConvention.NotDeletedFilter>();
HasManyToMany(x => x.Webcams)
.Schema("mod_list_management")
.Table("DynSuppliesWebcams")
.ParentKeyColumn("SupplyId")
.ChildKeyColumn("WebcamId")
.ApplyChildFilter<DeletedAtIsNullFilterConvention.NotDeletedFilter>()
.Cascade.All()
.Inverse()
;
}
}
public class HardwareSupplier
{
public virtual int Id { get; protected set; }
public virtual int LastDataVersion { get; set; }
public virtual string Name { get; set; } = "";
public virtual IDictionary Attributes { get; set; }
public virtual Currency PreferredCurrency { get; set; }
private readonly ISet<Supply> supplies = new HashSet<Supply>();
public virtual IEnumerable<Supply> Supplies
{
get { return supplies; }
}
}
public class HardwareSupplierMap : ClassMap<HardwareSupplier>
{
public HardwareSupplierMap()
{
Schema("mod_list_management");
Table("DynHardwareSuppliers");
Id(x => x.Id);
Map(x => x.LastDataVersion);
Map(x => x.Name);
References(x => x.PreferredCurrency, "PreferredCurrencyId").Cascade.None();
ApplyFilter<DeletedAtIsNullFilterConvention.NotDeletedFilter>();
HasMany(x => x.Supplies)
.KeyColumn("HardwareSupplierId")
.ApplyFilter<DeletedAtIsNullFilterConvention.NotDeletedFilter>()
.Cascade.AllDeleteOrphan()
.Inverse()
.LazyLoad();
DynamicComponent(x => x.Attributes, c =>
{
c.Map<DateTime>("LastSupplyReceivedAt").Nullable();
});
}
}
public class Currency
{
public virtual int Id { get; protected set; }
public virtual int LastDataVersion { get; set; }
public virtual string Name { get; set; }
public virtual string Code { get; set; }
public virtual int NumericCode { get; set; }
public virtual byte MinorUnitDecimalDigits { get; set; }
}
public class CurrencyMap : ClassMap<Currency>
{
public CurrencyMap()
{
Schema("dbo");
Table("arCurrencies");
Id(x => x.Id);
Cache.NonStrictReadWrite();
Map(x => x.LastDataVersion);
Map(x => x.Name, "Currency");
Map(x => x.Code, "Code");
Map(x => x.NumericCode, "NumericCode");
Map(x => x.MinorUnitDecimalDigits, "MinorUnit");
ApplyFilter<DeletedAtIsNullFilterConvention.NotDeletedFilter>();
}
}
public class DeletedAtIsNullFilterConvention :
IClassConvention,
IClassConventionAcceptance,
IHasManyConvention,
IHasManyConventionAcceptance,
IHasManyToManyConvention,
IHasManyToManyConventionAcceptance
{
public void Apply(IClassInstance instance)
{
instance.ApplyFilter<NotDeletedFilter>();
}
public void Accept(IAcceptanceCriteria<IClassInspector> criteria)
{
criteria.Expect(x => x.EntityType.HasProperty("DeletedAt"));
}
public void Apply(IOneToManyCollectionInstance instance)
{
instance.ApplyFilter<NotDeletedFilter>();
}
public void Accept(IAcceptanceCriteria<IOneToManyCollectionInspector> criteria)
{
criteria.Expect(x => x.ChildType.HasProperty("DeletedAt"));
}
public void Apply(IManyToManyCollectionInstance instance)
{
instance.ApplyFilter<NotDeletedFilter>();
}
public void Accept(IAcceptanceCriteria<IManyToManyCollectionInspector> criteria)
{
criteria.Expect(x => x.ChildType.HasProperty("DeletedAt"));
}
public class NotDeletedFilter : FilterDefinition
{
public const string FilterName = "notDeleted";
public NotDeletedFilter()
{
WithName(FilterName)
.WithCondition("DeletedAt IS NULL");
}
}
}
}
In version 5.1.7 this code generates that output:
Testing NHibernate Many To Many relationship
V: 5.1.0.0
session.QueryOver<Webcam>().List();
NHibernate: SELECT this_.Id as id1_0_0_, this_.LastDataVersion as lastdataversion2_0_0_, this_.Manufacturer as manufacturer3_0_0_, this_.Model as model4_0_0_, this_.Price as price5_0_0_, this_.HasMic as hasmic6_0_0_, this_.DeletedAt as deletedat7_0_0_ FROM mod_list_management.DynWebcams this_ WHERE this_.DeletedAt IS NULL
var count1 = webcamExist[0].Supplies.Count;
NHibernate: SELECT supplies0_.WebcamId as webcamid1_1_1_, supplies0_.SupplyId as supplyid2_1_1_, supply1_.Id as id1_2_0_, supply1_.LastDataVersion as lastdataversion2_2_0_, supply1_.Number as number3_2_0_, supply1_.DeletedAt as deletedat4_2_0_, supply1_.HardwareSupplierId as hardwaresupplierid5_2_0_ FROM mod_list_management.DynSuppliesWebcams supplies0_ left outer join mod_list_management.DynSupplies supply1_ on supplies0_.SupplyId=supply1_.Id WHERE supply1_.DeletedAt IS NULL AND supply1_.DeletedAt IS NULL and supplies0_.WebcamId=@p0;@p0 = 123241 [Type: Int32 (0:0:0)]
var webcamByGet = session.Get<Webcam>(123241);
var list = webcamByGet.Supplies.ToList();
var count2 = webcamByGet.Supplies.Count;
count2 = 0
NHibernate: INSERT INTO dbo.arCurrencies (LastDataVersion, Currency, Code, NumericCode, MinorUnit) VALUES (@p0, @p1, @p2, @p3, @p4); select SCOPE_IDENTITY();@p0 = 100500 [Type: Int32 (0:0:0)], @p1 = 'My currency' [Type: String (4000:0:0)], @p2 = '' [Type: String (4000:0:0)], @p3 = 42 [Type: Int32 (0:0:0)], @p4 = 7 [Type: Byte (1:0:0)]
And in 5.2.0 the same code generates that output:
Testing NHibernate Many To Many relationship
V: 5.2.0.0
session.QueryOver<Webcam>().List();
NHibernate: SELECT this_.Id as id1_0_0_, this_.LastDataVersion as lastdataversion2_0_0_, this_.Manufacturer as manufacturer3_0_0_, this_.Model as model4_0_0_, this_.Price as price5_0_0_, this_.HasMic as hasmic6_0_0_, this_.DeletedAt as deletedat7_0_0_ FROM mod_list_management.DynWebcams this_ WHERE this_.DeletedAt IS NULL
var count1 = webcamExist[0].Supplies.Count;
NHibernate: SELECT supplies0_.WebcamId as webcamid1_1_1_, supplies0_.SupplyId as supplyid2_1_1_, supply1_.Id as id1_2_0_, supply1_.LastDataVersion as lastdataversion2_2_0_, supply1_.Number as number3_2_0_, supply1_.DeletedAt as deletedat4_2_0_, supply1_.HardwareSupplierId as hardwaresupplierid5_2_0_ FROM mod_list_management.DynSuppliesWebcams supplies0_ left outer join mod_list_management.DynSupplies supply1_ on supplies0_.SupplyId=supply1_.Id and supply1_.DeletedAt IS NULL WHERE supply1_.DeletedAt IS NULL and supplies0_.WebcamId=@p0;@p0 = 123241 [Type: Int32 (0:0:0)]
NHibernate: SELECT supply0_.Id as id1_2_0_, supply0_.LastDataVersion as lastdataversion2_2_0_, supply0_.Number as number3_2_0_, supply0_.DeletedAt as deletedat4_2_0_, supply0_.HardwareSupplierId as hardwaresupplierid5_2_0_ FROM mod_list_management.DynSupplies supply0_ WHERE supply0_.Id=@p0;@p0 = 46801 [Type: Int32 (0:0:0)]
var webcamByGet = session.Get<Webcam>(123241);
var list = webcamByGet.Supplies.ToList();
var count2 = webcamByGet.Supplies.Count;
count2 != 0
NHibernate: INSERT INTO dbo.arCurrencies (LastDataVersion, Currency, Code, NumericCode, MinorUnit) VALUES (@p0, @p1, @p2, @p3, @p4); select SCOPE_IDENTITY();@p0 = 100500 [Type: Int32 (0:0:0)], @p1 = 'My currency' [Type: String (4000:0:0)], @p2 = '' [Type: String (4000:0:0)], @p3 = 42 [Type: Int32 (0:0:0)], @p4 = 7 [Type: Byte (1:0:0)]
In Version 5.2.0 especially this line is very important:
and supply1_.DeletedAt IS NULL WHERE supply1_.DeletedAt IS NULL
it is like this in 5.1.7:
WHERE supply1_.DeletedAt IS NULL AND supply1_.DeletedAt IS NULL
So, I'm not sure about which one is true but I am unable to apply child filter of "DeletedAt is NULL". Am I doing something wrong?
Metadata
Metadata
Assignees
Labels
No labels