NHibernate: How to set DynamicUpdate on all Entities? - nhibernate

How can I set DynamicUpdate and DynamicInsert on all my entities?
It works perfectly when I put it together with my mapping code, but I would like to specify it only once for my entire project.
I could not find an option when creating the Session or in the Configuration.
Any ideas?

I use fluent nhibernate so I would change them like this:
var fluentConfiguration = Fluently.Configure(NHibernate.Cfg.Configuration().Configure())
.Mappings(m =>
m.FluentMappings
.AddFromAssemblyOf<OrderMap>()
.Conventions.AddFromAssemblyOf<PascalCaseColumnNameConvention>())
.ProxyFactoryFactory("NHibernate.Bytecode.DefaultProxyFactoryFactory, NHibernate");
var config = fluentConfiguration.BuildConfiguration();
foreach(PersistentClass persistentClass in config.ClassMappings)
{
persistentClass.DynamicUpdate = true;
}
var sessionFactory = config.BuildSessionFactory();

When using mapping-by-code its as simple as this:-
var mapper = new ModelMapper();
mapper.BeforeMapClass += (mi, t, map) =>
{
map.DynamicUpdate(true);
map.DynamicInsert(true);
};
...
Just make sure you remove it from ALL your class by class mappings as they will override this convention.
Just to complete if you do want to override any class definitions then you can also use
mapper.AfterMapClass += (mi, t, map) => { ... }

Related

Asp.Net Core AddAutoMapper Dynamic from Multi Projects

I want to register AutoMapper form different project each project have it's public function to register his functions
like this
public static class Binder
{
public static IServiceCollection UseInjection(this IServiceCollection services)
{
services.AddAutoMapper(typeof(MappingProfile));
}
}
if i do it on each layer it's not working .
i need to write everything ones
like this : (work)
services.AddAutoMapper(
typeof(Project1.Mapping.MappingProfile),
typeof(Project2.Mapping.MappingProfile),
typeof(Project3.Mapping.MappingProfile));
i try to scan the folder for the dll's and take the type to register ones :
var target = typeof(JustForLocation).Assembly;
bool DefaultFilter(Assembly x) => true;
var path = Path.GetDirectoryName(target.Location) ?? throw new Exception();
var assembliesToLoad = Directory.GetFiles(path, "*.dll").
Select(dll => Assembly.LoadFile(dll))
.Where(DefaultFilter)
.ToList();
assembliesToLoad.Add(target);
var types = assembliesToLoad.SelectMany(a => a.GetExportedTypes()).Where(w => w.BaseType == typeof(AutoMapper.Profile)).ToArray();
services.AddAutoMapper(types);
but it's still throw error from the AutoMappe that say:
AutoMapperMappingException: Missing type map configuration or unsupported mapping. Mapping types
any advise why it's happen ?
// Auto mapper registration
services.AddAutoMapper(typeof(Startup).Assembly, typeof(BaseRepository).Assembly);
// Dapper Column Mapping
SqlMapper.SetTypeMap(typeof(Sample), new ColumnTypeMapper(typeof(Sample)));

Fluent nHibernate - Query Cache not working with "session.Query" and Cacheable()

Did't get any QueryCacheHitCount. The Source Code looks like:
nHibernate 3.3.1.4000, FluentnHibernate 1.3.0.733
Config:
Factory = Fluently.Configure()
.ExposeConfiguration(c =>
c.SetProperty(NHibernate.Cfg.Environment.GenerateStatistics, "true"))
.Database(
MsSqlConfiguration.MsSql2008.ConnectionString(c => c.Is("DATA SOURCE=localhost;PERSIST SECURITY INFO=True;USER ID=AAA;Password=AAA"))
.ShowSql()
)
.Mappings(x => x.FluentMappings.AddFromAssemblyOf<Localization.NHibernate.Article>())
.ExposeConfiguration(BuildDatabase)
.Cache(
x => x.UseSecondLevelCache()
.UseQueryCache()
.ProviderClass<NHibernate.Cache.HashtableCacheProvider>())
.BuildSessionFactory();
Execute:
using (var tx = session.BeginTransaction())
{
Factory.Statistics.Clear();
for (int i = 0; i < 10; i++)
{
Article s = session.Query<Article>().Cacheable().Where(x => x.Name == "O").SingleOrDefault();
}
Console.WriteLine(Factory.Statistics.QueryCacheHitCount);
Console.WriteLine(Factory.Statistics.SecondLevelCacheHitCount);
Console.WriteLine(Factory.Statistics.QueryExecutionCount);
}
Only if i change the cache config and add my private QueryCacheFactory with .QueryCacheFactory<CacheFactory>() than it works (But i ignore the IsUpToDate check)
public class CacheFactory : NHibernate.Cache.IQueryCacheFactory
{
public NHibernate.Cache.IQueryCache GetQueryCache(string regionName, NHibernate.Cache.UpdateTimestampsCache updateTimestampsCache, Settings settings, IDictionary<string, string> props)
{
return new MyStandardQueryCache(settings, props, updateTimestampsCache, regionName);
}
private class MyStandardQueryCache : NHibernate.Cache.StandardQueryCache
{
public MyStandardQueryCache(Settings settings, IDictionary<string, string> props, NHibernate.Cache.UpdateTimestampsCache updateTimestampsCache, string regionName)
: base(settings, props, updateTimestampsCache, regionName) { }
protected override bool IsUpToDate(Iesi.Collections.Generic.ISet<string> spaces, long timestamp)
{
return true; // SET TO TRUE than it's hitting the cache
}
}
}
I had a similar problem and from a I can remember, the results of the query are cached using the creation time of the session or the transaction. Try using a session for first query and different one for the following, doing that you should receive cache hits.

passing object with collection from domain to modelDTO with nhibernate

above is code which I use to manipulate with data from my domain to dto model, which I use for wcf serialization. My question is how to pass object mother with collection of childrens into MotherDTO. With current code situation I pass only data without collection children. Do I need to use session in line and to add session MotherDTO dto = new MotherDTO(data, session); and to use that session to retreive collection of childrens in dto. If so, how ? Please help.
Regards,
public MotherDTO GetMotherData()
{
using (ISession session = instance.OpenSession())
{
using (ITransaction tx = session.BeginTransaction())
{
Mother data = session.Query<Mother>()
.Fetch(x => x.Childrens)
.FirstOrDefault();
tx.Commit();
MotherDTO dto = new MotherDTO(data);
return dto;
}
}
}
MotherDTO.cs
public MotherDTO(Mother x)
{
Name = x.Name;
List<Children>Childrens= new List<Children>();
foreach (Children obj in x.Childrens)
{
States.Add(obj);
}
}
Mother.cs
public virtual string Name
{
get { return _Name; }
set
{
_Name = value;
}
}
public virtual Iesi.Collections.Generic.ISet<Children> Childrens
{
get
{
return _Childrens;
}
set
{
if (_Childrens == value)
return;
_Childrens = value;
}
}
Since you're already (eager) loading your Children collection you can use Automapper to populate your DTOs.
If you want to know how to configure Automapper to work with nested collection you can read here:
Mapper.CreateMap<Order, OrderDto>()
.ForMember(dest => dest.OrderLineDtos, opt => opt.MapFrom(src => src.OrderLines));
Mapper.CreateMap<OrderLine, OrderLineDto>()
.ForMember(dest => dest.ParentOrderDto, opt => opt.MapFrom(src => src.ParentOrder));
Mapper.AssertConfigurationIsValid();

How to set the property as lazyloading in fluent-hibernate with auto-mapping?

I am using auto-mapping with flent-hibernate for mapping. I would like if there is a way to set the reference property to be as 'lazy-loading' using IConvention or similar, rather than using separate mapping class?
firstly, i believe that lazy is the default behaviour.
you can test it quite easily-
[TestMethod]
public void TestLazyLoading()
{
Airport firstObject = null;
using (ISession session = this.SessionFactory.OpenSession())
{
using (ITransaction transaction = session.BeginTransaction())
{
ObjectDAO dao = new ObjectDAO(session, CurrentUser);
firstObject = dao.GetObject();
transaction.Commit();
}
}
Assert.IsFalse(NHibernateUtil.IsInitialized(firstObject.Children));
}
if you want to specify explicitly lazy / eager, use the following inside your MappingOverride class:
mapping.HasMany(x => x.Employees)
//.Not
.LazyLoad()
;
To adjust automappings you can use IAutoMappingOverride<SomeEntity>. You can change there exact property that you need

Formula Mapping in NHibernate to Functions in SQLite or Override Mapping

i found the following article http://ayende.com/Blog/archive/2009/04/28/nhibernate-unit-testing.aspx to help me unit test my NHibernate application. Most of my tests are working fine but a strange error has been thrown. From looking at the SQL generated i believe the following fluent mapping is causing the problems:
Map(x => x.IsValid).Formula("CASE WHEN dbo.NumPosts(UserID) = 5 THEN 1 ELSE 0 END");
You'll notice the call to dbo.NumPosts which is a user defined function within my database. I know there's other ways i could've mapped this property but this is just used as an example. Basically i need to know how to map this using SQLite.
Edit:
After further thoughts would, is it possible to override the mapping for this field in my unit testing project? Here's my current configuration:
private static ISessionFactory CreateSessionFactory() {
return Fluently.Configure()
.Database(SQLiteConfiguration.Standard.InMemory().ShowSql())
.Mappings(m => m.FluentMappings
.AddFromAssembly(typeof(Role).Assembly)
.Conventions.AddFromAssemblyOf<EnumConvention>())
.ExposeConfiguration(c => _configuration = c)
.BuildSessionFactory();
}
I don't wish to re-define all the mappings as this would take some time and would become un-maintainable.
I'd appreciate the help. Thanks
In reference to the answer in your comment, I was able to get a static bool property to work.
Still I didn't like relying on a global bool variable so I decided to dig further. In NHibernate 3.0 they added events to the Configuration object. In particular I was able to take advantage of the new BeforeBind event on the Configuration object.
I rewrote slightly your CreateSessionFactory() method to show how I did it.
NOTE: In my formula's I always write them as dbo.NumPosts, and the event handler will remove the 'dbo.' if we are running within a SQLite Dialect.
private static ISessionFactory CreateSessionFactory()
{
return Fluently.Configure()
.Database(SQLiteConfiguration.Standard.InMemory().ShowSql())
.Mappings(m => m.FluentMappings
.AddFromAssembly(typeof (Role).Assembly)
.Conventions.AddFromAssemblyOf<EnumConvention>())
.ExposeConfiguration(c =>
{
c.BeforeBindMapping += BeforeBindMappingHandler;
_configuration = c;
})
.BuildConfiguration()
.BuildSessionFactory();
}
private static void BeforeBindMappingHandler(object sender, BindMappingEventArgs e)
{
if (!(e.Dialect is SQLiteDialect)) return;
var properties = e.Mapping.RootClasses
.SelectMany(r => r.Properties)
.Where(p => p is HbmProperty)
.Cast<HbmProperty>()
.Where(p => p.Formulas.Any());
foreach (var hbmProperty in properties)
hbmProperty.formula = hbmProperty.formula.ToLower().Replace("dbo.", "");
}
Problem solved! I was able to say:
[SQLiteFunction(Name = "NumPosts", Arguments = 1, FuncType = FunctionType.Scalar)]
public class NumPosts : SQLiteFunction {
public override object Invoke(object[] args) {
...
}
}
Now all i had to do was add a setting to add the dbo prefix infront of my functions. This is then set to blank in the test project.