I get an exception: Unrecognised method call in epression a.B.Count() when I run:
var query = session.QueryOver<A>()
.Where(a => a.B.Count() > 0)
.List();
The following code works:
var query1 = session.QueryOver<A>().List();
var query2 = query1.Where(a => a.B.Count() > 0);
Any ideas? Thanks.
Edit:
Here is my mappings. I'm using NHibernate 3.1.0.4000:
Models:
public class A
{
public virtual int Id { get; private set; }
public virtual ICollection<B> Bs { get; set; }
}
public class B
{
public virtual int Id { get; private set; }
}
Mappings:
public class AMappings : ClassMap<A>
{
public AMappings()
{
Id(x => x.Id);
HasMany(x => x.Bs).LazyLoad();
}
}
public class BMappings : ClassMap<B>
{
public BMappings()
{
Id(x => x.Id);
}
}
Rest of my code:
class Program
{
static void Main(string[] args)
{
// Create connection string
string connectionString = new System.Data.SqlClient.SqlConnectionStringBuilder()
{
DataSource = #".\r2",
InitialCatalog = "TestNHibernateMappings",
IntegratedSecurity = true
}.ConnectionString;
// Create SessionFactory
ISessionFactory sessionFactory = Fluently.Configure()
.Database(MsSqlConfiguration
.MsSql2008.ConnectionString(connectionString)
.ShowSql())
.Mappings(m => m.FluentMappings
.Add(typeof(AMappings))
.Add(typeof(BMappings)))
.ExposeConfiguration(BuildSchema)
.BuildConfiguration()
.BuildSessionFactory();
// Test
var session = sessionFactory.OpenSession();
// This line works OK
var query1 = session.Query<A>()
.Where(a => a.Bs.Count() > 0);
// This line throws exception: Unrecognised method call in epression a.Bs.Count()
var query2 = session.QueryOver<A>()
.Where(a => a.Bs.Count() > 0);
}
static void BuildSchema(Configuration cfg)
{
new SchemaExport(cfg).Create(false, true);
}
}
QueryOver is not LINQ.
Your second code snippet works because it's retrieving ALL THE RECORDS and using LINQ-to-objects in memory.
What you should do is:
session.Query<A>()
.Where(a => a.B.Count() > 0)
.ToList();
or better yet:
session.Query<A>()
.Where(a => a.B.Any())
.ToList();
Query is an extension method, you need to add using NHibernate.Linq;
Related
below default code in controller working fine
public ProductController(appDbContext parmContext)
{
_context = parmContext;
}
now I want to add DAL and in that, getting error creating object of type appDbContext, what to pass/set for parmContext?
below is the connection in Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
services.AddDbContext<appDbContext>(config =>
{
config.UseMySql(Configuration.GetConnectionString("PreSales"));
});
}
Below is the code I want to use
public IEnumerable<ProductStatusMaster> GetProductStatusFRdal()
// here I ant to create object of DBcontext (i.e. _context)
{
try
{
var msm = _context.ProductStatusMaster
.Where(s => s.ActiveYn == 1 )
.OrderBy(s => s.Status)
.ToList();
return msm;
}
catch
{
throw;
}
}
Let me get an answer.
There are 2 ways to realize code you want.
1) Through Controller DI.
2) Through Service Locator pattern (antipattern).
By the code:
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
services.AddDbContext<appDbContext>(config =>
{
config.UseMySql(Configuration.GetConnectionString("PreSales"));
});
}
you set up dependency for DbContext and configure connection parameters. So, for the first method you should pass the dependency through controller. Possible code will be like this:
public class MyTestAppController
{
private appDbContext _context;
public MyTestApController(appDbContext externalAppDbContext)
{
_context = externalAppDbContext;
}
public IEnumerable<ProductStatusMaster> GetProductStatusFRdal()
{
try
{
var msm = _context.ProductStatusMaster
.Where(s => s.ActiveYn == 1 )
.OrderBy(s => s.Status)
.ToList();
return msm;
}
catch
{
throw;
}
}
}
2) Using Service Locator pattern
In this case you should use IServiceProvider dependency. Code example like this:
public class MyTestAppController
{
private IServiceProvider _provider;
public MyTestAppController(IServiceProvider provider) => _provider = provider;
public IEnumerable<ProductStatusMaster> GetProductStatusFRdal()
{
var _context = _provider.GetService<appDbContext>();
try
{
var msm = _context.ProductStatusMaster .Where(s => s.ActiveYn == 1 )
.OrderBy(s => s.Status) .ToList(); return msm;
}
catch { throw; }
}
}
I'm trying to inject dependencies im my models that NHibernate creates.
What I'm trying to do is the same here: http://fabiomaulo.blogspot.com.br/2008/11/entities-behavior-injection.html
But my container is Autofac.
So, I've found https://www.nuget.org/packages/Autofac.Extras.NHibernate/
I saw the post http://chadly.net/2009/05/dependency-injection-with-nhibernate-and-autofac/ that I've think is the origin of the Autofac.Extras.NHibernate.
My problem is that the code in Autofac.Extras.NHibernate and described in Chad post are different.
Looking at the source code I (think) figured out how to set the BytecodeProvider using:
Cfg.Environment.BytecodeProvider = new AutofacBytecodeProvider(Container, new DefaultProxyFactoryFactory(), new DefaultCollectionTypeFactory());
But now, I'm getting an exception when I tried to retrieve data from database:
[PropertyAccessException: could not set a property value by reflection setter of NHibernate.Autofac2.App_Start.Model.User.Id]
If I comment the line where I set BytecodeProvider the code works.
I created a POC to simulate:
My model:
public class User
{
private readonly ISomeService _someService;
public User(ISomeService someService)
{
this._someService = someService;
}
public virtual long Id { get; set; }
public virtual string Name { get; set; }
public virtual string GetTranslate
{
get { return this._someService != null ? this._someService.T(this.Name) : " No Translate" + this.Name; }
}
}
My mapping:
public class UserMap : ClassMap<User>
{
public UserMap()
{
Id(x => x.Id);
Map(x => x.Name)
.Length(16)
.Not.Nullable();
}
}
Creation of the Autofac container and SessionFactory using Fluent Nhibernate:
// Create your builder.
var builder = new ContainerBuilder();
builder.RegisterType<SomeService>().As<ISomeService>();
builder.RegisterType<User>().As<IUser>();
Container = builder.Build();
SessionFactory = Fluently.Configure()
.Database(MsSqlConfiguration.MsSql2005.ConnectionString("Data Source=(local);Initial Catalog=NHibernate.Autofac;User ID=test;Password=102030;Pooling=True"))
.Mappings(m => m.FluentMappings.AddFromAssemblyOf<MvcApplication>())
.ExposeConfiguration(config => config.Properties.Add("use_proxy_validator", "false"))
.ExposeConfiguration(config =>
{
//config.Properties.Add("proxyfactory.factory_class", "");
Cfg.Environment.BytecodeProvider = new AutofacBytecodeProvider(Container, new DefaultProxyFactoryFactory(), new DefaultCollectionTypeFactory());
new SchemaExport(config).Drop(false, false);
new SchemaExport(config).Create(false, true);
})
.BuildSessionFactory();
Well, I've found a solution that works for me.
Now, I'm using NHibernate.DependencyInjection.
The IEntityInjector implemenation:
public class EntityInjector : IEntityInjector
{
private readonly IContainer _container;
public EntityInjector(IContainer container)
{
_container = container;
}
public object[] GetConstructorParameters(System.Type type)
{
var constructor = type.GetConstructors().FirstOrDefault();
if (constructor != null)
return constructor.GetParameters().Select(a => a.ParameterType).Select(b => this._container.Resolve(b)).ToArray();
return null;
}
}
And in Global.asax:
Initializer.RegisterBytecodeProvider(new EntityInjector(Container));
SessionFactory = Fluently.Configure()
.Database(MsSqlConfiguration.MsSql2005.ConnectionString("Data Source=(local);Initial Catalog=NHibernate.Autofac;User ID=XXX;Password=XXXX;Pooling=True"))
.Mappings(m => m.FluentMappings.AddFromAssemblyOf<MvcApplication>())
.ExposeConfiguration(config => config.Properties.Add("use_proxy_validator", "false"))
.ExposeConfiguration(config =>
{
new SchemaExport(config).Drop(false, false);
new SchemaExport(config).Create(false, true);
})
.BuildSessionFactory();
I am trying to use NHibernate Envers to log an additional field "user". I have followed several code examples that seem to vary a bit when it comes to syntax, probably because some of them are a bit out of date. However I can't get it to work.
I'm getting this exception:
Only one property may have the attribute [RevisionNumber]!
My Custom Revision Entity:
public class CustomRevisionEntity
{
public virtual int Id { get; set; }
public virtual DateTime RevisionTimestamp { get; set; }
public virtual Guid UserIdentityId { get; set; }
public override bool Equals(object obj)
{
if (this == obj) return true;
var revisionEntity = obj as CustomRevisionEntity;
if (revisionEntity == null) return false;
var that = revisionEntity;
if (Id != that.Id) return false;
return RevisionTimestamp == that.RevisionTimestamp;
}
public override int GetHashCode()
{
var result = Id;
result = 31 * result + (int)(((ulong)RevisionTimestamp.Ticks) ^ (((ulong)RevisionTimestamp.Ticks) >> 32));
return result;
}
}
My IRevisionListener:
public class RevInfoListener : IRevisionListener
{
public void NewRevision(object revisionEntity)
{
var casted = revisionEntity as CustomRevisionEntity;
if (casted != null)
{
casted.UserIdentityId = Guid.NewGuid(); // TODO
}
}
}
First I use mapping by code to map the entity:
_modelMapper.Class<CustomRevisionEntity>(entity =>
{
entity.Property(x => x.Id);
entity.Property(x => x.RevisionTimestamp);
entity.Property(x => x.UserIdentityId);
});
Then I configure Envers and NHibernate
var enversConf = new FluentConfiguration();
enversConf.SetRevisionEntity<CustomRevisionEntity>(x => x.Id, x => x.RevisionTimestamp, new RevInfoListener());
enversConf.Audit<OrganizationEntity>().Exclude(x => x.Version);
configuration.IntegrateWithEnvers(enversConf); // This is the nh-configuration
The last line gives me the exception:
Only one property may have the attribute [RevisionNumber]!
Anyone have any ideas? Myself I would speculate that the default revision entity is still used somehow and when I try to register my custom revision entity this happens.
The error message occurred because the Id property was being mapped twice.
In our mapping class we had this
_modelMapper.BeforeMapClass += (modelInspector, type, classCustomizer) => classCustomizer.Id(type.GetProperty("Id"), (idMapper) =>
{
idMapper.Access(Accessor.Property);
idMapper.Generator(Generators.GuidComb);
});
Then we tried mapping Id again as a property of the CustomRevisionEntity
The final mapping:
_modelMapper.Class<CustomRevisionEntity>(entity =>
{
entity.Id<int>(x => x.Id, mapper => mapper.Generator(Generators.Identity));
entity.Property(x => x.RevisionDate);
entity.Property(x => x.UserIdentityId);
});
FluentNHibernate version 1.3.0.727
I have the following custom TableNameConvention:
public class TableNameConvention : IClassConvention, IClassConventionAcceptance
{
public void Accept(IAcceptanceCriteria<IClassInspector> criteria)
{
criteria.Expect(x => x.TableName, Is.Not.Set);
}
public void Apply(IClassInstance instance)
{
instance.Table(instance.EntityType.Name + "s");
}
}
I have the following entity mapping:
public class UserMap : ClassMap<User>
{
public UserMap()
{
Id(x => x.Id).GeneratedBy.Identity();
Map(x => x.Email).Not.Nullable().Length(200);
Map(x => x.FirstName).Length(100);
Map(x => x.LastName).Length(100);
Map(x => x.Password).Not.Nullable().Length(30);
}
}
I'm generating database like this:
var configuration = Fluently.Configure()
.Mappings(m => m.FluentMappings
.AddFromAssemblyOf<IEntity>()
.Conventions.Add<TableNameConvention>())
.BuildConfiguration();
var schema = new SchemaExport(configuration);
schema.Drop(false, true);
schema.Create(false, true);
Then generating database User entity table is still generated as User but not Users as I want it to be. It seams that Accept method fails. Is this FluentNHibernate bug?
Remove this code
public void Accept(IAcceptanceCriteria<IClassInspector> criteria)
{
criteria.Expect(x => x.TableName, Is.Not.Set);
}
because it is not needed and maybe even not what you want. FNH has three values internally for each property (e.g. tablename)
value set explicitly in classmap
value set by convention
defaultvalue
and it uses what it finds in this order valueInEffect = explicitValue ?? conventionValue ?? defaultValue
I am trying to run lazy queries against raven db and get the counts on total matching results. I am finding when I query against a static index, a lazy search does not initialize the statistics when the query is materialized, but otherwise it comes back all right.
Below is the test to prove this behaviour.
[TestFixture]
public class CanSearchLazily
{
private const int ServerPort = 8085;
private readonly string _serverAddress = #"http://localhost:{0}".For(ServerPort);
[Test]
public void CanGetTotalResultsFromStatisticsOnLazySearchAgainstDynamicIndex()
{
CanGetTotalResultsFromStatisticsOnLazySearchAgainstAnIndex();
}
[Test]
public void CanGetTotalResultsFromStatisticsOnLazySearchAgainstStaticIndex()
{
CanGetTotalResultsFromStatisticsOnLazySearchAgainstAnIndex("UserByFirstName");
}
private void CanGetTotalResultsFromStatisticsOnLazySearchAgainstAnIndex(string indexName = "")
{
BuilderSetup.DisablePropertyNamingFor<User, string>(x => x.Id);
var users = Builder<User>.CreateListOfSize(2000).All()
.With(x => x.FirstName = GetRandom.FirstName())
.With(x => x.LastName = GetRandom.LastName())
.Build();
using (GetNewServer())
using (var store = new DocumentStore { Url = _serverAddress }.Initialize())
{
using (var session = store.OpenSession())
{
users.ForEach(session.Store);
session.SaveChanges();
IndexCreation.CreateIndexes(typeof(UserByFirstName).Assembly, store);
session.Query<User, UserByFirstName>().Customize(x => x.WaitForNonStaleResults()).ToList();
}
using (var session = store.OpenSession())
{
var names = session.Query<User>().Select(u => u.FirstName).Distinct().Take(15).ToList();
RavenQueryStatistics stats;
var query = string.IsNullOrEmpty(indexName)
? session.Query<User>().Statistics(out stats).Where(x => x.FirstName.In(names))
: session.Query<User>(indexName).Statistics(out stats).Where(x => x.FirstName.In(names));
var results = query.Take(8).Lazily();
Assert.AreEqual(8, results.Value.ToList().Count);
Assert.AreEqual(DateTime.Now.Year, stats.IndexTimestamp.Year, "the index should have the current year on its timestamp");
Assert.IsTrue(stats.TotalResults > 0, "The stats should return total results");
}
}
}
protected RavenDbServer GetNewServer(bool initializeDocumentsByEntitiyName = true)
{
var ravenConfiguration = new RavenConfiguration
{
Port = ServerPort,
RunInMemory = true,
DataDirectory = "Data",
AnonymousUserAccessMode = AnonymousUserAccessMode.All
};
if (ravenConfiguration.RunInMemory == false)
IOExtensions.DeleteDirectory(ravenConfiguration.DataDirectory);
var ravenDbServer = new RavenDbServer(ravenConfiguration);
if (initializeDocumentsByEntitiyName)
{
using (var documentStore = new DocumentStore
{
Url = _serverAddress
}.Initialize())
{
new RavenDocumentsByEntityName().Execute(documentStore);
}
}
return ravenDbServer;
}
}
[Serializable]
public class User
{
public string Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
public class UserByFirstName : AbstractIndexCreationTask<User>
{
public UserByFirstName()
{
Map = users => from user in users
select new {user.FirstName};
}
}