Fluent NHibernate PersistentSpecification Test fails - c#

I currently have these Maps
public class CountryMap : ClassMap<Country>
{
public CountryMap()
{
Table("tblCountry");
Id(x => x.Id, "intCountryId");
Map(x => x.Name, "strCountryName");
HasMany(x => x.FlagImages)
.Table("tblImage")
.KeyColumn("intRelId")
.Where("intObjId=29")
.Not.Cascade.All();
}
}
public class ImageMap : ClassMap<Image>
{
public ImageMap()
{
Table("tblImage");
Id(x => x.Id, "intImgId");
Map(x => x.ObjId, "intObjId");
Map(x => x.RelId, "intRelId");
Map(x => x.ImageName, "strImage");
}
}
and the following persistent specification test:
PersistenceSpecification<Image>(session)()
.CheckProperty(r => r.Id, 1)
.CheckProperty(r => r.ImageName, "ss")
.CheckProperty(r => r.ObjId, (int)ObjectType.Country)
.CheckProperty(r => r.RelId, 102)
.VerifyTheMappings();
Somewhat the test of Image failed.
The failure message is
Assert.AreEqual failed. Expected:<(null)>. Actual:<NHibernate.Exceptions.GenericADOException: could not insert: [HansaCrew.Models.Images.Image][SQL: INSERT INTO tblImage (intObjId, intRelId, strImage) VALUES (?, ?, ?); select last_insert_rowid()] ---> System.Data.SQLite.SQLiteException: constraint failed
foreign key constraint failed
I've checked it for 2 days and haven't find the reason. Any help?

Okay, I got it.
The problem of this piece of code lies here
HasMany(x => x.FlagImages)
.Table("tblImage")
.KeyColumn("intRelId")
.Where("intObjId=29")
.Not.Cascade.All();
NHibernate automatically creates a foreign key constraint with tblImage, which has a lot of intRelIds which is not in the column of intCountryId in the table tblCountry. That's why the test fails saying foreign key constraint failure.
The way to solve this problem is to create a view in the database and then map the view into the Image model

Related

session.Save forces insert on id 0 relation objects - Fluent NHibernate

So yeah, I'm trying to insert a new entity on my database, which has some foreign keys pointing to auxiliar tables, which in this case shouldn't be updated.
It has 8 total foreign keys, which are all working but for one which has to be id = 0;
using (var session = FluentNHibernateHelper.OpenSession())
{
using (var transaction = session.BeginTransaction())
{
try
{
session.SaveOrUpdate(p);
transaction.Commit();
return p;
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
}
I guess there's no need to show the structure of the entity itself but for the map of the object:
References(x => x.Jerarquia).Column("TCODJERARQUIALIN").Cascade.All().Not.Nullable();
References(x => x.Conformidad).Column("TCODCONFORMIDADL").Cascade.All().Not.Nullable();
References(x => x.Tramitacion).Column("TCODESTADOTRAMIT").Cascade.All().Not.Nullable();
References(x => x.SistemaReferencia).Column("TCODSISTEMAREFER").Cascade.All().Not.Nullable();
References(x => x.Vigencia).Column("TCODVIGENCIALINE").Cascade.All().Not.Nullable();
References(x => x.CategoriaGeometrica).Column("TCODCATGEOMETRIC").Cascade.All().Not.Nullable();
References(x => x.Territorio1).Column("TCODIDTERRITORI1").Cascade.All().Not.Nullable();
References(x => x.Territorio2).Column("TCODIDTERRITORI2").Cascade.All().Not.Nullable();
Structure of the rest of the mappings comes to be like this, no matter which the related item is:
Id(x => x.TCODJERARQUIA).Column("TCODJERARQUIA").Not.Nullable();
Map(x => x.TTEXDESCJERAR_ES).Column("TTEXDESCJERAR_ES").Not.Nullable();
Map(x => x.TTEXDESCJERAR_EU).Column("TTEXDESCJERAR_EU").Not.Nullable();
Table("TARLLJERAR");
To sum it up, if one of the foreign key items is id = 0, it wont set the foreign key but will insert a new item on aux table
How can i solve this issue?
Thanks in advance!

Fluent NHibernate bulk data insert

I need to transfer some data to other db, but when I start this mssql server freeze.
ds2 row count about 250,000. What am I doing wrong?
every time I try same funcion first looks working and after give error on random row. maybe 5, 95 or 280. until error records looks valid.
string inlineSql = "Select * from album";
DataSet ds2 = SqlHelper.ExecuteDataset(ConnectionString, CommandType.Text, inlineSql);
for (int i = 0; i < ds2.Tables[0].Rows.Count; i++)
{
Entity.Album.Album album = new Entity.Album.Album();
album.AlbumName = ds2.Tables[0].Rows[i]["AlbumName"].ToString();
album.WebSite = (Entity.Artist.WebSite)Convert.ToInt16(ds2.Tables[0].Rows[i]["WebSite"]);
album.Year = ds2.Tables[0].Rows[i]["Year"].ToString();
Entity.Artist.Artist artist = Entity.Artist.Artist.READ.ById(Convert.ToInt32(ds2.Tables[0].Rows[i]["ArtistId"]));
if (artist != null)
{
artist.AddAlbum(album);
album.Save();
}
}
AddAlbum Method
public virtual void AddAlbum(Album.Album album)
{
album.Artist = this;
AlbumList.Add(album);
}
Save Method
using (var session = NHibernateHelper.OpenSession())
{
using (var transaction = session.BeginTransaction())
{
session.SaveOrUpdate(x);
transaction.Commit();
}
}
Error on session.SaveOrUpdate(x);
Error :
An exception of type 'NHibernate.Exceptions.GenericADOException'
occurred in NHibernate.dll but was not handled in user code
Additional information: could not insert: [Entity.Album.Album][SQL:
INSERT INTO [Album]
(AlbumName, WebSite, Year, ArtistId) VALUES (?, ?, ?, ?); select
SCOPE_IDENTITY()]
AlbumMap
public class AlbumMap : ClassMap<Album>
{
public AlbumMap()
{
Id(x => x.AlbumId);
Map(x => x.AlbumName);
Map(x => x.WebSite).CustomType<short>();
Map(x => x.Year);
HasMany(x => x.LyricList).Table("Lyric").KeyColumn("AlbumId").Cascade.All().Not.LazyLoad();
References(x => x.Artist).Column("ArtistId").ForeignKey("ArtistId").Fetch.Join();
}
}
ArtistMap
public class ArtistMap : ClassMap<Artist>
{
public ArtistMap()
{
Id(x => x.ArtistId);
Map(x => x.ArtistName);
Map(x => x.ArtistURL);
Map(x => x.ImgName);
Map(x => x.ImgURL);
Map(x => x.Alfabet);
Map(x => x.SeoLink);
Map(x => x.WebSite).CustomType<short>();
HasMany(x => x.AlbumList).Table("Album").KeyColumn("ArtistId").Cascade.All().Not.LazyLoad();
}
}
More Exception
The INSERT statement conflicted with the FOREIGN KEY constraint
"FKA0CE20AA48AC4CAD". The conflict occurred in database "LYRICSWEB",
table "dbo.Artist", column 'ArtistId'. The statement has been
terminated.
There are some indications, which should lead to the answer. We can see that the error is:
Additional information: could not insert: [Entity.Album.Album][SQL: INSERT INTO [Album]
(AlbumName, WebSite, Year, ArtistId) VALUES (?, ?, ?, ?); select SCOPE_IDENTITY()]
while we are loading artist correct way...
Entity.Artist.Artist artist = Entity.Artist.Artist.READ
.ById(Convert.ToInt32(ds2.Tables[0].Rows[i]["ArtistId"]));
The issue would be in incorrect collection mapping. The reference from Albumt to Artist seem to be correct:
public AlbumMap()
{
..
References(x => x.Artist)
.Column("ArtistId")
.ForeignKey("ArtistId")
.Fetch.Join();
}
But the other end of that relation is mapped like this:
// wrong
public ArtistMap()
{
..
HasMany(x => x.AlbumList)
.Table("Album")
.KeyColumn("AlbumId") // wrong
.Cascade.All().Not.LazyLoad();
}
Both above relations are the same! They are only mapped from different ends (from collection item perspective and from collection owner perespective).
That means that the mapping column must be the same, i.e. not "AlbumId" but "ArtistId"
// correct
public ArtistMap()
{
..
HasMany(x => x.AlbumList)
.Table("Album")
.KeyColumn("ArtistId") // this is the relation
.Cascade.All().Not.LazyLoad();
}
Because NHibernate loads some artist, and its collection of AlubmList.. it could lead to some unexpected insert statements... fix of that mapping should help...
Second thing to mention: Inverse()
We are working with Album instances... and we are assigning their relation to collection holder - Artist. This is good and suggested way how to do that. Good.
But we can profit from NHibernate feature called Inverse() which will reduce few SQL statements... and make all the insert more simple... so extend your Artist mapping like this:
// correct
public ArtistMap()
{
..
HasMany(x => x.AlbumList)
.Table("Album")
.KeyColumn("ArtistId") // this is the relation
.Cascade.All()
.Not.LazyLoad()
.Inverse(); // ESSENTIAL improvement of generated SQL
}
Check this for more details

Strange Foreign Key constraint in fluent mapped SQLite

I have a model written using FluentNhibernate and I am trying to create some test data in an in-memory SQLite database.
var fConfig =
Fluently.Configure()
.Database(config)
.Mappings(m => m.FluentMappings.AddFromAssembly(Assembly.GetAssembly(exampleClass))
.Conventions.Add(AutoImport.Never())
.Conventions.Add(new SQLiteGeometryTypeConvention())
.Conventions.Add(FluentNHibernate.Conventions.Helpers.DefaultLazy.Never()))
.ExposeConfiguration(cfg => configuration = cfg);
The problem I am getting is that one of the tables is created like this in the generated sql something like this :
create table myTable (
myID integer primary key autoincrement,
...{skip normal columns}
ForeignTable1ID INT,
ParentID BIGINT,
constraint FK1A2E045AFEC6908F foreign key (ForeignTable1ID) references ForeignTable1,
constraint FK1A2E045ABB4EBD1F foreign key (ParentID) references Parent,
constraint FKE21911CF6853D06E foreign key (myID) references Parent
)
I don't want that third constraint but don't know what's causing it!
The effect being that I can only create records in myTable which have valid foreign keys BUT ALSO have a myID value which exists in the Parent table. This is unnecessary, and I can't see what's causing it.
The mapping file looks like this:
Table("dbo.PalslagInventering");
Id(x => x.myId).Column("myID");
References(x => x.ForeignTable1).Column("ForeignTable1ID");
References(x => x.Parent).Column("ParentID");
Map(x => x.{other columns here});
HasMany(x => x.Child).KeyColumn("myID");
HasOne(x => x.Child2).ForeignKey("MyID");
HasMany(x => x.Child2).KeyColumn("MyID").ForeignKeyConstraintName("Child2");
HasMany(x => x.Child3).KeyColumn("MyID").ForeignKeyConstraintName("Child3");
The parent table (being referenced) has a simple
public virtual IList<MyTable> myTableRecords { get; private set; }
Type of code mapped as:
HasMany(x => x.myTableRecords)
.KeyColumn("myID")
.Inverse();
What is causing the "foreign key" reference back to it's own myId?
The error seems to be:
HasMany(x => x.myTableRecords)
.KeyColumn("myID")
.Inverse();
Where it's the Child table (i.e. "MyTable") which has the ID "myID" and the KeyColumn should point to the Parent table (i.e. the foreign key in "MyTable").
So:
HasMany(x => x.myTableRecords)
.KeyColumn("ParentID")
.Inverse();
Seems to have fixed the problem. That the error was in the parent class's mapping file meant I missed it at first.

Foreign Key to a table with 2 columns primary key (CompositeId)

I've defined the primary key as following:
CompositeId()
.KeyProperty(x => x.Id)
.KeyProperty(x => x.Type);
I've tried the following:
References(x => x.EntityWith2ColsPK);
And failed with:
Foreign key (Fk_MyEntity_EntityWith2ColsPK:MyEntities [Fk_EntityWith2ColsPK])) must have same number of columns as the referenced primary key (EntityWith2ColsPKs [Id, Type])
How can I reference EntityWith2ColsPK from another entity?
Update:
I've tried the following (according to AlfeG's comment):
HasMany<EntityWith2ColsPK>(x => x.EntityWith2ColsPK).KeyColumns.Add("Id", "Type").Cascade.All();
Which failed with:
Custom type does not implement UserCollectionType: EntityWith2ColsPK
But anyway I don't want a 1 to many relation, I want a 1 to 1 relation. Still, I can't make either of them work.
Also, I've tried:
HasOne<EntityWith2ColsPK>(x => x.EntityWith2ColsPK).PropertyRef(x => x.Id).PropertyRef(x => x.Type);
Which fails with:
NHibernate.MappingException : property not found: Type on entity EntityWith2ColsPK
What can I do for this to really work?
I managed to achieve something in the db.. but yet, for some reason I suspect it maps the property "Type" twice, because I want it to be both part of the Primary Key, and part of the Foreign Key..
This is what I did:
References(x => x.EntityWith2ColsPK).Columns("EntityWith2ColsPKId", "Type").Formula("Id = :EntityWith2ColsPKId AND Type = :Type");
But I received the following exception:
System.IndexOutOfRangeException : Invalid index 8 for this SqlParameterCollection with Count=8.
Because the mapping of this entity is same as EntityWith2ColsPK:
CompositeId()
.KeyProperty(x => x.Id)
.KeyProperty(x => ((ILocalizedEntity) x).Language);
HELP!
You can use something like this since you aren't using cascade anyway on your Reference
References(x => x.EntityWith2ColsPK)
.Columns(new string[] { "ID", "TYPE" })
.Not.Update()
.Not.Insert();

NHibernate fluent update problem (one to many relation)

I have a object OtherFaclilityEntity which contains a IList of OtherFcs objects, and the mapping is as follows:
public OtherFacilityMap()
{
Schema("SOME");
Table("OTHER_FACILITY");
Id(x => x.Id, "OTHER_FACILITY_S").GeneratedBy.TriggerIdentity();
Map(x => x.RowCreator, "ROW_CREATOR");
Map(x => x.RowCreateDate, "ROW_CREATE_DATE");
Map(x => x.Description, "DESCRIPTION");
Map(x => x.ExistenceKdNm, "R_EXISTENCE_KD_NM");
References(x => x.FacilityClassItem, "FACILITY_CLASS_S").LazyLoad(Laziness.False).Fetch.Join().Not.Insert().Not.Update();
HasMany(x => x.FacilityCmList).KeyColumn("WHOLE_S").Fetch.Subselect().Not.LazyLoad();
}
When i try to do a SaveOrUpdate on the OtherFacility entity, it also updates all the entities in the FacilityCmList, which is fine, but in the last sql that is run tries to remove all relations between the parent and the child objects:
NHibernate.SQL: 2011-07-19 10:29:33,111 [361] DEBUG NHibernate.SQL [(null)] - UPDATE SOME.FACILITY_CMS SET WHOLE_S = null WHERE WHOLE_S = :p0;:p0 = '26021842'
I assume it has something to do with my mapping, any ideas?
After reading NHibernate sets Foreign Key in secondary update rather than on initial insert violating Not-Null Constrain on key column i found that i needed to add Inverse to the HasMany relation.
HasMany(x => x.FacilityCmList).KeyColumn("WHOLE_S").Fetch.Subselect().Inverse().Not.LazyLoad();

Categories

Resources