Mapping Geometry from SQLServer2008 to .NET (NHibernate 4.0.0.4000) - fluent-nhibernate

I try to map a SqlServer2008 geometry with FluentNHibernate. I am using NHibernate version 4.0.0.4000. I installed NHibernate.Spatial, NetTopologySuite, GeoAPI and NHibernate with FluentNhibernate all with NUget.
My Fluent mapping looks like this:
public class ArealMap: ClassMap<Areal>
{
public Areal()
{
Table("Areal");
Id(x => x.Id).Column("Id").GeneratedBy.Identity();
Map(x => x.Geometry).Column("Geometry").CustomType(typeof(MsSql2008GeometryType));
}
}
public class Areal
{
....
public virtual Geometry Geometry{ get; set; }
}
With NHibernate 4.0.0.4000 Areal will always be mapped to null instead of the value in the DB (of type geometry). The non-geometry properties are mapped correctly.
This mapping was working perfectly in NHibernate 3.3.3.
I also added
.Dialect<MsSql2008GeometryDialect>())
to my fluent configuration....
I think all the dlls have the correct version installed, as I got them via NUget. I don´t think its an NH /Fluent NH issue as all my other mappings are working fine...
Is there a new syntax for mapping sql server geometry to NHibernate in the release for NH 4.0? I don´t know what I am missing..
EDIT:
When I change the mapping to:
Map(x => x.Geometry).Column("Geometry").CustomType(typeof(MsSqlLegacyGeometryType));
I don´t get null in Geometry anymore, instead my polygon in database is written
to a mapped as a Geometry of type point with different coordinates....
I think this problem might be caused by different versions of Microsoft.SqlServer.Types beeing used... SqlServer2008 uses version 10.0 and NHibernate.Spatial.MsSql uses version 11.0...
Or there may be breaking changes in GeoApi or NetTopologySuite...
EDIT:
Okay, I found the source of the problem....
I am using Sql Server 2008, so it uses Microsoft.SqlServer.Types.dll in
C:\Windows\assembly\GAC_MSIL\Microsoft.SqlServer.Types\10.0.0.0__89845dcd8080cc91\
However, the NHibernate.Spatial dlls which work with NHibernate 4.0 expect higher SQLServer and reference Microsoft.SqlServer.Types.dll version 11 in
C:\Windows\assembly\GAC_MSIL\Microsoft.SqlServer.Types\11.0.0.0_89845dcd8080cc91\
Anyone know how to fix this issue?
I think I have to checkout / clone one of the NHibernate.Spatial projects and manually reference Microsoft.SqlServer.Types.dll version 10 and then recompile the project...
I am lost however as where to start. What projects do I need to reoompile? NetTopologySuite which is referenced by NHibernate.Spatial or only NHibernate.Spatial?

While perhaps not ideal since it's forcing you to use an older version, I was able to solve a mismatch involving the Geometry DLLS after an NHibernate upgrade by using a binding redirect on the assembly declaration in the web.config
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="Microsoft.SqlServer.Types" publicKeyToken="89845dcd8080cc91" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-11.0.0.0" newVersion="10.0.0.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>

Related

Deleted database & migration file, can't make new migrations nor revert old migrations, what now?

My workflow with my ASP.NET Core app: Whenever I make changes that affect the database, I revert the old migration, make a new migration, apply it. Because this is still early development I think it makes sense to not pollute the project with lots of migration files. Usually I call this temporary migration file Initial, hoping that one of them will actually become the initial migration file.
As a result, I typically have 3 files in my Data/Migrations subfolder:
00000000000000_CreateIdentitySchema.cs that was provided for me a long time ago by the project template;
somenumbers_Initial.cs;
ApplicationDbContextModelSnapshot.cs
So the commands I would type in this workflow would look like this, if I remember correctly:
Update-Database CreateIdentitySchema
Remove-Migration
Add-Migration Initial
Update-Database
This time I made a mistake... I don't remember what exactly happened, I typed something incorrect instead of the above commands and then I was silly enough that (a) manually removing the Initial migration file and (b) Dropping the database would be enough to restart the test db from scratch.
I was wrong.
My hopes were that Add-Migration Initial would create a valid migration file corresponding to the current state of the models and a subsequent Update-Database would recreate the db. Instead this is what happens:
PM> Add-Migration initial
Microsoft.EntityFrameworkCore.Infrastructure[10403]
Entity Framework Core 3.0.0 initialized 'ApplicationDbContext' using provider 'Microsoft.EntityFrameworkCore.SqlServer' with options: None
The name 'initial' is used by an existing migration.
??? Really? Well let's try to remove this migration:
Microsoft.EntityFrameworkCore.Infrastructure[10403]
Entity Framework Core 3.0.0 initialized 'ApplicationDbContext' using provider 'Microsoft.EntityFrameworkCore.SqlServer' with options: None
No file named '20190727172711_initial.cs' was found. You must manually remove the migration class 'initial'.
System.NullReferenceException: Object reference not set to an instance of an object.
at Microsoft.EntityFrameworkCore.Design.Internal.CSharpHelper.Literal(String value)
at Microsoft.EntityFrameworkCore.Migrations.Design.CSharpSnapshotGenerator.GeneratePropertyAnnotations(IProperty property, IndentedStringBuilder stringBuilder)
at Microsoft.EntityFrameworkCore.Migrations.Design.CSharpSnapshotGenerator.GenerateProperty(String builderName, IProperty property, IndentedStringBuilder stringBuilder)
at Microsoft.EntityFrameworkCore.Migrations.Design.CSharpSnapshotGenerator.GenerateProperties(String builderName, IEnumerable`1 properties, IndentedStringBuilder stringBuilder)
at Microsoft.EntityFrameworkCore.Migrations.Design.CSharpSnapshotGenerator.GenerateEntityType(String builderName, IEntityType entityType, IndentedStringBuilder stringBuilder)
at Microsoft.EntityFrameworkCore.Migrations.Design.CSharpSnapshotGenerator.GenerateEntityTypes(String builderName, IReadOnlyList`1 entityTypes, IndentedStringBuilder stringBuilder)
at Microsoft.EntityFrameworkCore.Migrations.Design.CSharpSnapshotGenerator.Generate(String builderName, IModel model, IndentedStringBuilder stringBuilder)
at Microsoft.EntityFrameworkCore.Migrations.Design.CSharpMigrationsGenerator.GenerateSnapshot(String modelSnapshotNamespace, Type contextType, String modelSnapshotName, IModel model)
at Microsoft.EntityFrameworkCore.Migrations.Design.MigrationsScaffolder.RemoveMigration(String projectDir, String rootNamespace, Boolean force, String language)
at Microsoft.EntityFrameworkCore.Design.Internal.MigrationsOperations.RemoveMigration(String contextType, Boolean force)
at Microsoft.EntityFrameworkCore.Design.OperationExecutor.RemoveMigrationImpl(String contextType, Boolean force)
at Microsoft.EntityFrameworkCore.Design.OperationExecutor.RemoveMigration.<>c__DisplayClass0_0.<.ctor>b__0()
at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.<>c__DisplayClass3_0`1.<Execute>b__0()
at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.Execute(Action action)
Object reference not set to an instance of an object.
???? I must manually remove the migration class ?? Where is this migration class?
Let's do some text searching in the project dir... The only interesting file that shows up is myprojectname.csproj where I have stuff like this:
<Compile Remove="Data\Migrations\20190412182930_initial.cs" />
<Compile Remove="Data\Migrations\20190412182930_initial.Designer.cs" />
<Compile Remove="Data\Migrations\20190628205310_initial.cs" />
<Compile Remove="Data\Migrations\20190628205310_initial.Designer.cs" />
<Compile Remove="Data\Migrations\20190720205411_initial.cs" />
<Compile Remove="Data\Migrations\20190720205411_initial.Designer.cs" />
<Compile Remove="Data\Migrations\20190720205837_initial.cs" />
<Compile Remove="Data\Migrations\20190720205837_initial.Designer.cs" />
I don't think this is relevant here (the numbers strings do not match).
I looked into ApplicationDbCOntextModelSnapshot but there seems to be no such class called initial there...
What to do now? How to proceed?
If you dropped the database then it's easy. Delete the migrations folder.
Then run
add-migration Initial
update-database
Also, I tend to remove any <Compile Remove="" /> from the project file.

Invalid value for key attachdbfilename after renaming connectionString

I am building the sample MvcMovie tutorial for ASP.NET MVC 4. I'm using EntityFramework Code First features and created a connectionString as follows.
<add name="MoveDBContext"
connectionString="Data Source=(LocalDB)\v11.0;AttachDbFilename=|DataDictionary|\Movies2.mdf;Integrated Security=True"
providerName="System.Data.SqlClient"
/>
Everything worked fine at this point. But then I realized that I named my connection string MoveDBContext instead of MovieDBContext and, being the perfectionist I renamed it. After doing this I now receive an error in my MoviesController/Index method.
public class MoviesController : Controller
{
private MovieDBContext db = new MovieDBContext();
public ActionResult Index()
{
return View(db.Movies.ToList()); // Error: Invalid value for key 'attachdbfilename'
}
...
}
If I change the name back to MoveDBContext the error goes away.
Can anyone tell me where this original name is being referenced?
EF, by default, looks for a connection string with the same name as the type that extends DbContext.
Or, better put by Scott:
By default, when you create a DbContext class with EF code-first, it
will look for a connection-string that matches the name of the
context-class. Since we named our context class “NerdDinners”, it
will by default look for and use the above “NerdDinners” database
connection-string when it is instantiated within our ASP.NET
application.
Edit:
After looking closer, I think your connection string is the problem. You've got DataDictionary instead of DataDirectory. Try this (line feeds added for readability):
<add name="MovieDBContext"
connectionString="Data Source=(LocalDB)\v11.0;
AttachDbFilename=|DataDirectory|\Movies.mdf;
Integrated Security=True"
providerName="System.Data.SqlClient" />
Apparently, as Ken said, the MoveDBContext was not being referenced.
I removed the entire connectionString from the web.config and everything still functioned correctly.
So, it still begs the question, "How did Visual Studio know to create a database in my SQLExpress instance?" and "Where is that configured at?"

NHibernate 3 and castle proxy: myList.Contains is broken

I'm trying to upgrade a C# .NET 3.5 project from NH 1.2 to NH 3.1. I'm having a hard time with a: myListOfT.contains(someT).
myListOfT contains someT, and myListOfT[0] seems to be someT (I can see it with Visual Studio "spy"). HashCodes are the same. myListOfT[0] and someT are both Castle.Proxies.T...
What is wrong with my code and NH 3.1?
Let's say that I want to know I some User belongs to a Workplace or a child one's.
public bool UserBelongToWorkplace(Workplace wp, User u)
{
if (wp.Users.Contains(u)) return true;
foreach (Workplace subWp in wp.Workplaces)
{
return UserBelongToWorkplace(subWp, u);
}
}
In this context: wp.Users : ReadOnlyCollection<User> (hides IList<Users>)
Nhibernate config:
<property name="cache.use_second_level_cache">true</property>
<property name="proxyfactory.factory_class">
NHibernate.ByteCode.Castle.ProxyFactoryFactory, NHibernate.ByteCode.Castle
</property>
At runtime, the function always returns false, even if the workplace really contains the user.
With debugger/traces I can check that wp.Users[0] == u (same Id, same HashCode). Both objects are proxyfied. It was working fine before the upgrade to Nhibernate 3.1.
I am pretty sure it has something to do with lazy-loading/proxy as we already had kinda issues, but it was involving type comparison (CProxy_User and User for instance).
Make sure both Equals() and GetHashCode() are correctly implemented for User

Unable to cast object of type 'NHibernate.Caches.SysCache.SysCacheProvider' to type 'NHibernate.Cache.ICacheProvider'

I'm using NHibernate 2.1.2 via Castl ActiveRecord. I wanted to set up second level cache using SysCache. But I got error:
Unable to cast object of type 'NHibernate.Caches.SysCache.SysCacheProvider' to type 'NHibernate.Cache.ICacheProvider'.
How can I correct this?
I'm guessing that you have some assemblies locally in your project and others in the GAC which have a version mismatch as Mauricio is saying. Make sure that NHibernate.Caches.SysCache.dll is in your bin folder (for your website), is the correct version and check that you don't have it in the GAC.
I found the reason. It was a nasty problem from ours. My team have merged all Castle ActiveRecord related assemblies together with ilmerge.exe and suppose named it Company.NHibernate.dll. I have not merged NHibernate.Caches.SysCache.dll with Company.NHibernate.dll. I have just put NHibernate.Caches.SysCache.dll alongside of Company.NHibernate.dll and mentioned name of NHibernate.Caches.SysCache in provider_class.
When I merged NHibernate.Caches.SysCache.dll with Company.NHibernate.dll and mentioned name of Company.NHibernate.dll in provider_class instead, everything went OK.
Thanks all users that tried to help me.

Fluent NHibernate no data being returned

I have been successfully using NHibernate, but now I am trying to move to Fluent NHibernate. I have created all of my mapping files and set up my session manager to use a Fluent Configuration. I then run my application and it runs successfully, but no data is returned.
There are no errors or any indication that there is a problem, but nothing runs.
when using NHibernate, if I don't set my hbm xml files as an embedded resource, this same thing happens. This makes me wonder what I have to set my Map classes to. Right now, they are just set to Compile, and they are compiled into the dll, which I can see by disassembling it.
Does anyone have any thoughts as to what may be happening here?
Thanks
private ISessionFactory GetSessionFactory()
{
return Fluently.Configure()
.Database(
IfxOdbcConfiguration
.Informix1000
.ConnectionString("Provider=Ifxoledbc.2;Password=mypass;Persist Security Info=True;User ID=myuser;Data Source=mysource")
.Dialect<InformixDialect1000>()
.ProxyFactoryFactory<ProxyFactoryFactory>()
.Driver<OleDbDriver>()
.ShowSql()
)
.Mappings(
x => x.FluentMappings.AddFromAssembly(System.Reflection.Assembly.GetExecutingAssembly())
//.ExportTo("C:\\mappings")
)
.BuildSessionFactory();
}
Does the executing assembly contain the fluent mapping classes? I would try:
.Mappings(x => x.FluentMappings.AddFromAssemblyOf<MappedType>())
Where MappedType is a class that has a fluent mapping.
They should just be set to compile, that's fine. Nothing special needed here. The problem is most likely in your fluent configuration rather than the mapping.